package com.itheima.health.service.impl;

import com.itheima.health.common.MessageConst;
import com.itheima.health.common.PasswordConstant;
import com.itheima.health.common.RedisConst;
import com.itheima.health.dao.MemberDao;
import com.itheima.health.dao.OrderDao;
import com.itheima.health.dao.OrderSettingDao;
import com.itheima.health.dao.SetMealDao;
import com.itheima.health.exception.BusinessRuntimeException;
import com.itheima.health.pojo.dto.OrderDTO;
import com.itheima.health.pojo.entity.*;
import com.itheima.health.service.OrderService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.ZoneId;
import java.util.Date;

@Service
public class OrderServiceImpl implements OrderService {
    @Autowired
    private OrderDao orderDao;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private MemberDao memberDao;
    @Autowired
    private OrderSettingDao orderSettingDao;
    @Autowired
    private SetMealDao setMealDao;

    /**
     * 体检预约
     * @param dto
     * @return
     */
    @Override
    public Order submit(OrderDTO dto) {
        //判断验证码
        //获取redis中刚存入的预约验证码
        String code = (String) redisTemplate.opsForValue().get(RedisConst.ORDER_VALIDATE_CODE_PREFIX + dto.getTelephone());
        //比对用户输入的验证码
        if (!code.equals(dto.getValidateCode())){
            //不同则抛出异常
            throw new BusinessRuntimeException(MessageConst.VALIDATECODE_ERROR);
        }
        //如果是新手机号自动注册为会员,加锁以防重复注册
        Member member;
        synchronized (this){
            member = memberDao.selectMemberByTelephone(dto.getTelephone());
            if ( member== null){
                member = Member.builder().phoneNumber(dto.getTelephone()).password(PasswordConstant.DEFAULT_PASSWORD).build();
                memberDao.add(member);
            }
        }
        //会员同一天同一个体检不能重复预约
        Order result = orderDao.selectByMemberIdAndOrderDateAndSetmealId(member.getId(),dto.getOrderDate(),dto.getSetmealId());
        if (result != null){
            throw new BusinessRuntimeException(MessageConst.SELECTED_DATE_CANNOT_ORDER);
        }
        //该体检预约约满，无法预约
        //实际已经预约的人数,Date类型转换为LocateDate类型，才能进行比较
        Date orderDate = dto.getOrderDate();
        LocalDate localDate = orderDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        Integer now = orderDao.getByNow(localDate);
        //查询设置的当日预约人数
        Integer number = orderSettingDao.selectNumberByDate(localDate);
        //查出数据如果为空是不能进行比较的，所以转成数字0
        now = now == null ? 0 : now;
        number = number == null ? 0 : number;
        if (number == 0){
            throw new BusinessRuntimeException("设置的当日预约人数为空");
        }
        if (now >= number){
            //预约人数已满
            throw new BusinessRuntimeException(MessageConst.ORDER_FULL);
        }
        //以上都没问题，可以插入预约数据了
        Order order = Order.builder()
                .memberId(member.getId())
                .orderDate(dto.getOrderDate())
                .orderType(Order.ORDERTYPE_WEIXIN)
                .orderStatus(Order.ORDERSTATUS_NO)
                .setmealId(dto.getSetmealId())
                .build();
        //需要主键返回id，前端需要
        orderDao.insert(order);
        return order;
    }

    /**
     * 根据订单id查询订单信息
     * @param id
     * @return
     */
    @Override
    public OrderShow findOrderById(Integer id) {
        //1.先根据订单id查询订单信息
        Order order = orderDao.selectById(id);
        OrderShow orderShow = new OrderShow();
        BeanUtils.copyProperties(order,orderShow);
        //2.根据订单信息的member_id和setmeal_id查询对应的会员信息和套餐信息
        Member member = orderDao.selectMemberById(order.getMemberId());
        Setmeal setmeal = setMealDao.selectsetMealById(order.getSetmealId());
        //3.封装订单信息到OrderShow中并返回
        if (member != null) {
            orderShow.setMember(member.getName());
        }
        if (setmeal != null) {
            orderShow.setSetmeal(setmeal.getName());
        }
        return orderShow;
    }
}
